﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ExecuteSQL.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Defines the ExecuteSQL type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Collaboris.Saf.Actions.SQL
{
    using Entities;
    
    using Engine;

    using SharePoint.Wss.Attributes;

    using Utils;

    /// <summary>
    /// The execute sql.
    /// </summary>
    [CollaborisClass(Title = "Executes a SQL Statement.", 
        ReleaseStatus = ReleaseStatus.Stable, 
        DisableDocumentation = false, 
        ContactAuthorEmail = "Support@Collaboris.co.uk", 
        Summary = "Allows a SQL statement to be run against a database as specified " + "by a supplied connection string.",
        UndoImplemented = true,
        ClassGuid = "{156E17A5-A7BA-4e1f-8A48-1BC341A7C622}")]
    public class ExecuteSQL : ActionBase<ExternalEngineWrapper<SQLScript>>
    {
        #region Constants and Fields

        /// <summary>
        /// The current script.
        /// </summary>
        private SQLScript currentScript;

        #endregion

        #region Helper Methods

        /// <summary>
        /// Executes the Action using the values passed in by the Data Entity
        /// and the <see cref="SafContext"/>.
        /// </summary>
        /// <param name="context">
        /// A valid <see cref="SafContext"/> containing properties to run the Action with.
        /// </param>
        /// <param name="entity">
        /// A Valid <see cref="T"/> containing the parameters with which to run the Action with.
        /// </param>
        /// <returns>
        /// A <see cref="ProcessStatus"/> signifying the outcome of processing the Action.
        /// </returns>
        protected override ProcessStatus DoAction(SafContext context, ExternalEngineWrapper<SQLScript> entity)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "ExecuteSQL", "DoAction");

            this.currentScript = entity.DoScript;
            if (this.currentScript == null)
            {
                return ProcessStatus.Skip;
            }

            this.ProcessScript();

            TraceHelper.TraceMethodEnd(TraceSwitch, "ExecuteSQL", "DoAction");

            return ProcessStatus.Success;
        }

        /// <summary>
        /// Undoes the action by attempting to roll back what was done in the Do.
        /// </summary>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <param name="entity">
        /// The data entityList.
        /// </param>
        /// <returns>
        /// A <see cref="ProcessStatus"/> indicating the outcome of the Undo on the Action.
        /// </returns>
        protected override ProcessStatus UndoAction(SafContext context, ExternalEngineWrapper<SQLScript> entity)
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "ExecuteSQL", "UndoAction");

            this.currentScript = entity.UndoScript;
            if (this.currentScript == null)
            {
                return ProcessStatus.Skip;
            }

            this.ProcessScript();

            TraceHelper.TraceMethodEnd(TraceSwitch, "ExecuteSQL", "UndoAction");

            return ProcessStatus.Success;
        }

        /// <summary>
        /// Checks the Data entity used by the Action for Validity
        /// </summary>
        /// <param name="context">The <see cref="SafContext"/> passed in by the SAF Engine.</param>
        /// <param name="entity">The data entity to Validate.</param>
        /// <param name="errors">List of <see cref="ValidationError"/>s</param>
        /// <param name="mode"><see cref="ProcessMode"/>signalling wheter we are Doing, or Undoing the action.</param>
        /// <returns>false if invalid; otherwise true.</returns>
        protected override bool IsValid(SafContext context, ExternalEngineWrapper<SQLScript> entity, ref System.Collections.Generic.List<ValidationError> errors, ProcessMode mode)
        {
            int currentCount = errors.Count;
            SQLScript script;
            if (mode == ProcessMode.Do)
            {
                script = entity.DoScript;
            }
            else
            {
                script = entity.UndoScript;
            }

            // Validate each object now.
            if (!script.Timeout.HasValue)
                script.Timeout = 5000;

            // Have we added errors ?
            return errors.Count == currentCount;
        }

        /// <summary>
        /// Processes the script.
        /// </summary>
        private void ProcessScript()
        {
            TraceHelper.TraceMethodStart(TraceSwitch, "ExecuteSQL", "ProcessScript");

            if (!string.IsNullOrEmpty(this.currentScript.ScriptFile))
            {
                SQLHelper.RunSQLFromFile(
                    this.currentScript.ScriptFile, this.currentScript.ConnectionString, this.currentScript.Timeout.Value);
            }

            if (!string.IsNullOrEmpty(this.currentScript.ScriptText.ToString()))
            {
                SQLHelper.RunSQLFromText(
                    this.currentScript.ScriptText.ToString(), this.currentScript.ConnectionString, this.currentScript.Timeout.Value);
            }

            TraceHelper.TraceMethodEnd(TraceSwitch, "ExecuteSQL", "ProcessScript");
        }

        #endregion
    }
}